<template>
  <div class="flex flex-col">
    <div class="flex flex-row items-center cursor-pointer" @click.stop="onUpdateModelValue" v-loading="!deviceInited">
      <div class="flex-1 min-w-0" @mouseleave="onMouseLeave" @mousedown.stop.prevent="onImgClick('mousedown', $event)"
        @mouseup="onImgClick('mouseup', $event)" @mousemove.prevent="onImgClick('mousemove', $event)">
        <img v-if="deviceInited" :src="deviceImg" @load="onImgLoad" />
      </div>
    </div>
    <div>
      mouse-position: {{ mousePosition }}
    </div>
    <div>
      <el-checkbox v-model="allModel">全体模式</el-checkbox>
    </div>
  </div>
</template>
<script setup>
import { computed, inject, onBeforeUnmount, onMounted, ref, shallowRef, toValue, watch, watchEffect } from 'vue';
import { v4 } from 'uuid'
import { io } from 'socket.io-client'

const $emits = defineEmits(['command'])
const serverUrl = ref('http://localhost:3000')
const props = defineProps({
  info: {
    type: Object,
    defaulat: () => ({})
  },
  refreshImageDelay: {
    type: Number,
    defaulat: 10000
  }
})
const requestIdKeys = {}
const allModel = ref(true)
const deviceInited = ref(true)
const deviceScreenKey = ref(1)
const deviceWidth = ref(0)
const deviceHeight = ref(0)
const imageBound = ref()
const mousePosition = ref()

const deviceId = computed(() => {
  if (props.info?.type === 'ip') {
    return `${props.info.host}:${props.info.port}`
  } else if (props.info?.type === 'device') {
    return `${props.info.key}`
  }

  return ''
})

const deviceImg = computed(() => {
  return serverUrl.value + '/get-device-image?deviceId=' + deviceId.value + '&deviceScreenKey=' + deviceScreenKey.value
})

// const socketRef = inject('socketRef')
const socketRef = shallowRef()

const onImgLoad = evt => {
  deviceWidth.value = evt.target.naturalWidth
  deviceHeight.value = evt.target.naturalHeight
  imageBound.value = evt.target.getBoundingClientRect()

  setTimeout(() => {
    deviceScreenKey.value++
  }, props.refreshImageDelay);
}

function calacXY(clientX, clientY) {
  const imageBoundValue = toValue(imageBound)
  const deviceWidthValue = toValue(deviceWidth)
  const deviceHeightValue = toValue(deviceHeight)
  let startX = clientX - imageBoundValue?.left || 0
  let startY = clientY - imageBoundValue?.top || 0

  let imageWidth = imageBoundValue?.width || 1
  let imageHeight = imageBoundValue?.height || 1

  if (startX < 0) {
    startX = 0
  }

  if (startY < 0) {
    startY = 0
  }

  return {
    x: Math.ceil(deviceWidthValue * (startX / imageWidth)),
    y: Math.ceil(deviceHeightValue * (startY / imageHeight))
  }
}

const mouseDownRef = shallowRef(false)
const mouseMoveRef = shallowRef(false)
const mouseUpRef = shallowRef(false)

function onMouseLeave(e) {
  if (mouseDownRef.value && mouseMoveRef.value) {
    $emits('command', {
      activeKey: props.info?.key,
      allModel: allModel.value,
      type: 'touchUp',
      data: {
        deviceId: props.info.key,
        x: mouseMoveRef.value.x,
        y: mouseMoveRef.value.y
      }
    })
  }
  mouseDownRef.value = false
  mouseUpRef.value = false
  mouseMoveRef.value = false
}
function onImgClick(type, e) {
  const clientX = e.clientX
  const clientY = e.clientY

  const pos = calacXY(clientX, clientY)
  console.log(type)

  if (type === 'mousemove') {
    mousePosition.value = calacXY(clientX, clientY)
    if (mouseDownRef.value) {
      $emits('command', {
        activeKey: props.info?.key,
        allModel: allModel.value,
        type: 'touchMove',
        data: {
          deviceId: props.info.key,
          x: pos.x,
          y: pos.y
        }
      })
      mouseMoveRef.value = {
        x: pos.x,
        y: pos.y
      }
    }
  } else if (type === 'mousedown') {
    mouseDownRef.value = true
    $emits('command', {
      activeKey: props.info?.key,
      allModel: allModel.value,
      type: 'touchDown',
      data: {
        deviceId: props.info.key,
        x: pos.x,
        y: pos.y
      }
    })
  } else if (type === 'mouseup') {
    $emits('command', {
      activeKey: props.info?.key,
      allModel: allModel.value,
      type: 'touchUp',
      data: {
        deviceId: props.info.key,
        x: pos.x,
        y: pos.y
      }
    })
    mouseDownRef.value = false
    onMouseLeave()
  }


  // sendCommand({
  //   type: 'tap',
  //   data: {
  //     deviceId: props.info.key,
  //     x: pos.x,
  //     y: pos.y
  //   }
  // })
}

const sendMsg = (type, msg) => {
  const socket = toValue(socketRef)

  if (!socket) {
    return
  }

  const requestId = v4()

  requestIdKeys[requestId] = true

  socket.emit(type, {
    requestId,
    data: msg
  })

  return requestId
}

const sendCommand = (data) => {
  sendMsg('command', data)
}

const ensureRequestId = (msg, callback) => {
  const requestId = msg.requestId

  if (requestIdKeys[requestId]) {
    delete requestIdKeys[requestId]
    callback(msg.data)
  }
}

const initDone = (msg) => {
  ensureRequestId(msg, data => {
    console.log('init-done', data)
    deviceInited.value = true
  })
}

let _refreshScreenInterval = null

const startRefreshScreen = () => {
  _refreshScreenInterval = setInterval(() => {
    deviceScreenKey.value++
  }, props.refreshImageDelay);
}

const stopRefreshScreen = () => {
  clearInterval(_refreshScreenInterval)
}

function onUpdateModelValue() {
  // const index = activeKeys.value.findIndex(k => k === props.info?.key)
  // if (index >= 0) {
  //   activeKeys.value.splice(index, 1)
  // } else {
  //   activeKeys.value.push(props.info.key)
  // }
}

watch(deviceInited, val => {
  // if (val) {
  //   startRefreshScreen()
  // } else {
  //   stopRefreshScreen()
  // }
})

function closeWebsocket() {
  socketRef.value?.close()
}

function initWebsocket(wsUrl) {
  closeWebsocket()

  const socket = io(wsUrl, {
    reconnection: false,
    retries: 0
  })
  socket.on('connect', () => {
    socketRef.value = socket
    sendMsg('init', props.info)
    socket.on('init-done', initDone)
  });

  socket.on('disconnect', () => {
    console.log('Disconnected from server');
    socketRef.value = null
  });
}

watch(() => props.info, val => {
  if (!val?.wsUrl) {
    return
  }

  // initWebsocket(val.wsUrl)
}, {
  immediate: true,
  deep: true
})

const lastPos = shallowRef()

function getTouchUp() {
  const deviceId = props.info.key
  let ret

  if (lastPos.value) {
    ret = {
      type: 'touchUp',
      data: {
        deviceId,
        x: lastPos.value.x,
        y: lastPos.value.y,
      }
    }
    lastPos.value = null
  }

  return ret
}

function getCommands(direction, moveCenter) {
  const deviceId = props.info.key
  const startPos = {
    x: moveCenter.x,
    y: moveCenter.y
  }
  const count = 5
  const step = moveCenter.distance / count

  const arr = [
    getTouchUp(),
    {
      type: 'touchDown',
      data: {
        deviceId,
        ...startPos
      }
    }
  ].filter(Boolean)

  for (let i of [1, 2]) {
    const pos = {
      x: moveCenter.x,
      y: moveCenter.y
    }

    switch (direction) {
      case 'left':
        pos.x -= i * step
        break
      case 'right':
        pos.x += i * step
        break
      case 'up':
        pos.y -= i * step
        break
      case 'down':
        pos.y += i * step
        break
    }

    arr.push({
      type: 'touchMove',
      data: {
        deviceId,
        ...pos
      }
    })
  }

  lastPos.value = { ...arr[arr.length - 1]?.data }

  return arr
}

defineExpose({
  get key() {
    return props.info?.key
  },
  sendCommandWithCommands(commands) {
    console.log('commands', commands)
    const type = commands.type
    const code = commands.code
    const allCodes = commands.allCodes || []
    const keyMap = props.info?.keyMap?.[code]
    const moveCenter = props.info?.moveCenter
    if (type === 'keydown' && keyMap) {
      sendCommand({
        type: 'tap',
        data: {
          deviceId: props.info.key,
          x: keyMap.x,
          y: keyMap.y
        }
      })
    } else if (type === 'keydown' && moveCenter.left === code) {
      sendCommand(getCommands('left', moveCenter))
    } else if (type === 'keydown' && moveCenter.up === code) {
      sendCommand(getCommands('up', moveCenter))
    } else if (type === 'keydown' && moveCenter.down === code) {
      sendCommand(getCommands('down', moveCenter))
    } else if (type === 'keydown' && moveCenter.right === code) {
      sendCommand(getCommands('right', moveCenter))
    } else if (type === 'keyup' && [moveCenter.left, moveCenter.up, moveCenter.down, moveCenter.right].includes(code)) {
      sendCommand(getTouchUp())
    } else if (type && commands.data) {
      sendCommand({
        type, data: commands.data
      })
    }
  }
})

onBeforeUnmount(() => {
  // const socket = toValue(socketRef)
  // stopRefreshScreen()
  // sendMsg('close-device', props.info)
  // socket?.off('init-done', initDone)
  // closeWebsocket()
})
</script>
<style lang="scss" scoped></style>